using System.Collections.Generic;
using BlockeyEssentials;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using BlockeyEssentials.Input;
using Microsoft.Xna.Framework.Input;
using Blockey.GameplayScreens;

namespace Blockey.GameObjects3D
{
    public abstract class Person3D : Moveable3D
    {
        public Person3D(Game oGame, ControllingPlayer oPlayer, Alliance oTeamSide)
        {
            m_oControllingPlayer = oPlayer;
            _Radius = 1.75f;

            _HelmetDrawable = new DrawableModel(oGame.GraphicsDevice, oGame.Content, "Models\\Person\\Helmet", true);
            _HelmetDrawable.SetTransformation(Position, _RotationCurrent, 2.0f);

            _HeadDrawable = new DrawableModel(oGame.GraphicsDevice, oGame.Content, "Models\\Person\\Head", true);
            _HeadDrawable.SetTransformation(Position, _RotationCurrent, 2.0f);

            _BodyDrawable = new DrawableModel(oGame.GraphicsDevice, oGame.Content, "Models\\Person\\Body", true);
            _BodyDrawable.SetTransformation(Position, _RotationCurrent, 2.0f);

            _EyesDrawable = new DrawableModel(oGame.GraphicsDevice, oGame.Content, "Models\\Person\\Eyes", true);
            _EyesDrawable.SetTransformation(Position, _RotationCurrent, 2.0f);

            switch (oTeamSide)
            {
                case Alliance.Home:
                    {
                        //_HelmetDrawable.Material.AmbientColor = Color.Red.ToVector3() * 0.85f;
                        //_HelmetDrawable.Material.LightColor = Color.Red.ToVector3() * 0.15f;

                        //_BodyDrawable.Material.AmbientColor = Color.Red.ToVector3() * 0.85f;
                        //_BodyDrawable.Material.LightColor = Color.Red.ToVector3() * 0.15f;

                        //_HeadDrawable.Material.AmbientColor = Color.PeachPuff.ToVector3() * 0.85f;
                        //_HeadDrawable.Material.LightColor = Color.PeachPuff.ToVector3() * 0.15f;

                        //_EyesDrawable.Material.AmbientColor = Color.Black.ToVector3() * 0.85f;
                        //_EyesDrawable.Material.LightColor = Color.Black.ToVector3() * 0.15f;

                        //_HelmetDrawable.SetColor(Color.Red);
                        //_BodyDrawable.SetColor(Color.Red);
                        //_HeadDrawable.SetColor(Color.PeachPuff);
                        //_EyesDrawable.SetColor(Color.Black);
                        break;
                    }
                case Alliance.Away:
                    {                        
                        //_HelmetDrawable.SetColor(Color.Blue);
                        //_BodyDrawable.SetColor(Color.Blue);
                        //_HeadDrawable.SetColor(new Color(1.0f, 0.9f, 0.9f));
                        //_EyesDrawable.SetColor(Color.Black);
                        break;
                    }
                default:
                    {
                        //_HelmetDrawable.SetColor(Color.Gray);
                        //_BodyDrawable.SetColor(Color.Gray);
                        //_HeadDrawable.SetColor(Color.PeachPuff);
                        //_EyesDrawable.SetColor(Color.Gray);
                        break;
                    }
            }

            Condition = new Condition();
            Condition.ChangeTypeToNeutral();

            HeldObjects = new List<Moveable3D>();

            m_eTeam = oTeamSide;
        }

        public override void Move()
        {
            VelocityZ = MathHelper.Clamp(VelocityZ, -10, 0.5f);
            base.Move();
        }

        public abstract void Input(MatchScreen3D oMatchScreen);
        public abstract void InputClient(Camera3D oCamera);

        public void Tackle()
        {
            Condition.ChangeType(ConditionName.Tackling, 35);
            StartCondition(true);
        }
        public void Dive()
        {
            Condition.ChangeType(ConditionName.Diving, 20);
            StartCondition(true);
        }
        public void Hop()
        {
            Condition.ChangeType(ConditionName.Hopping, 10);
            StartCondition(true);
        }
        public void Fall()
        {
            Condition.ChangeType(ConditionName.Falling, Condition.ENDTIME_FALLING);
            StartCondition(true);
        }
        public void FallAfterHitting()
        {
            Condition.ChangeType(ConditionName.Falling, 30);
            StartCondition(true);
        }

        protected void ShootPuck(MatchScreen3D oMatchScreen)
        {
            var oHockeyMatch = oMatchScreen as HockeyGameScreen3D;
            if (oHockeyMatch == null) return;
            if (oHockeyMatch.Puck == null) return;

            var oPuck = oHockeyMatch.Puck;
            float oPower = (float)(Condition.Timer) / 60f;
            if (HeldObjects.Contains(oHockeyMatch.Puck))
            {
                BoundingBox oScoreBox;
                if (TeamSide == Alliance.Home)
                {
                    oScoreBox = oHockeyMatch.AwayGoal.ScoreArea;
                }
                else if (TeamSide == Alliance.Away)
                {
                    oScoreBox = oHockeyMatch.HomeGoal.ScoreArea;
                }
                else
                {
                    if (oPuck.PositionX < 0)
                    {
                        oScoreBox = oHockeyMatch.HomeGoal.ScoreArea;
                    }
                    else
                    {
                        oScoreBox = oHockeyMatch.AwayGoal.ScoreArea;
                    }
                }
                var oDirectionY = 0.0f;

                if (LastDirection.Y < 0)
                    oDirectionY = oScoreBox.Min.Y + oPuck.Radius * 1.5f;
                else if (LastDirection.Y > 0)
                    oDirectionY = oScoreBox.Max.Y - oPuck.Radius * 1.5f;
                else
                {
                    if (Position.Y < 0)
                        oDirectionY = oScoreBox.Min.Y + oPuck.Radius * 1.5f;
                    else
                        oDirectionY = oScoreBox.Max.Y - oPuck.Radius * 1.5f;
                }

                var oDestination = new Vector3(oScoreBox.Min.X, oDirectionY, 0);
                var oDirection = (oDestination - oPuck.Position);
                oDirection += (Vector3.UnitZ * oDirection.Length() * oPower);
                oDirection.Normalize();

                if (DebugShapeRenderer.ShowLines)
                {
                    DebugShapeRenderer.AddLine(Position, oPuck.Position + oDirection * 20, Color.Black, 2);
                }

                oPuck.Velocity = oDirection * 45f * oPuck.Magnitude;

                HeldObjects.Remove(oPuck);
            }
        }

        protected void PassPuck(MatchScreen3D oMatchScreen)
        {
            var oHockeyMatch = oMatchScreen as HockeyGameScreen3D;
            if (oHockeyMatch == null) return;
            if (oHockeyMatch.Puck == null) return;

            if (HeldObjects.Contains(oHockeyMatch.Puck))
            {
                var oPuck = oHockeyMatch.Puck;

                var oClosest = FindTeammateClosestToPuck(oHockeyMatch);
                if (oClosest == null) return;

                var oTeammateToPassTo = (Person3D)oClosest;
                var oDistance = Vector3.Distance(oTeammateToPassTo.Position, oPuck.Position) * 0.02f;
                var oDestination = new Vector3(
                    oTeammateToPassTo.PositionX + oTeammateToPassTo.VelocityX * 50 * oDistance,
                    oTeammateToPassTo.PositionY + oTeammateToPassTo.VelocityY * 50 * oDistance,
                    0);

                var oDirection = (oDestination - oPuck.Position);
                oDirection.Normalize();

                if (DebugShapeRenderer.ShowLines)
                { DebugShapeRenderer.AddLine(Position, oPuck.Position + oDirection * 20, Color.Black, 2); }

                oPuck.Velocity = oDirection * 40f * _Magnitude;
                HeldObjects.Remove(oPuck);
            }
        }

        public void SwitchPlayers(MatchScreen3D oMatchScreen)
        {
            if (oMatchScreen is HockeyGameScreen3D == false)
                return;

            var oHockeyMatch = (HockeyGameScreen3D)oMatchScreen;

            var oClosest = FindTeammateClosestToPuck(oHockeyMatch);
            if (oClosest == null) return;

            SwitchPlayersWith(oClosest);
        }

        public void SwitchPlayersWith(Person3D oPersonToSwitchWith)
        {
            oPersonToSwitchWith.Direction = Vector3.Zero;
            this.Direction = Vector3.Zero;

            var oTemp = oPersonToSwitchWith.ControllingPlayer;
            oPersonToSwitchWith.ControllingPlayer = this.ControllingPlayer;
            this.ControllingPlayer = oTemp;
        }

        private Skater FindTeammateClosestToPuck(HockeyGameScreen3D oHockeyMatch)
        {
            Puck3D oPuck = oHockeyMatch.Puck;
            if (oPuck == null) return null;

            List<Moveable3D> oTeammates = new List<Moveable3D>();
            foreach (var oPerson in oHockeyMatch.Skaters)
            {
                if (oPerson == this) continue;

                if (this.TeamSide == oPerson.TeamSide)
                    oTeammates.Add(oPerson);
            }

            return (Skater)Moveable3D.FindClosest(oPuck, oTeammates);
        }

        public virtual void Draw(GraphicsDevice oGraphics, Camera3D oCamera)
        {
            var oPos = _Position + _PositionShift;
            var oRot = new Vector3(_RotationCurrent.X + MathHelper.PiOver2, _RotationCurrent.Y, _RotationCurrent.Z);

            _HeadDrawable.SetTransformation(oPos, oRot, null);
            _HeadDrawable.Draw(oGraphics, oCamera);
            _HelmetDrawable.SetTransformation(oPos, oRot, null);
            _HelmetDrawable.Draw(oGraphics, oCamera);
            _BodyDrawable.SetTransformation(oPos, oRot, null);
            _BodyDrawable.Draw(oGraphics, oCamera);
            _EyesDrawable.SetTransformation(oPos, oRot, null);
            _EyesDrawable.Draw(oGraphics, oCamera);

            if (Condition.Name == ConditionName.Shooting)
            {
                Rectangle oRectangle = new Rectangle(500, 200, 150, 30);
                All.SpriteBatch_Debug.Draw(All.Texture_Square, oRectangle, null, Color.Black, 0, Vector2.Zero, SpriteEffects.None, 0.0f);
                oRectangle.Width = (int)((float)oRectangle.Width * ((float)Condition.Timer / 60f));
                All.SpriteBatch_Debug.Draw(All.Texture_Square, oRectangle, null, Color.Yellow, 0, Vector2.Zero, SpriteEffects.None, 1.0f);
            }
        }

        public override void DrawShadows(GraphicsDevice oGraphics, Camera3D oCamera)
        {
            if (_Shadow == null)
            {
                _Shadow = new DrawableCustom(oGraphics, All.Texture_Circle, false);
                _Shadow.SetTransformation(null, null, Radius * 0.85f);
                SetShadow();
            }

            var oPercent = 1 - (PositionZ * 0.025f);
            _Shadow.SetTransformation(_Position * new Vector3(1, 1, 0) + Vector3.UnitZ * 0.05f, null, Radius * 0.85f * (oPercent));
            oPercent = 1 - (PositionZ * 0.1f);
            _Shadow.Draw(oGraphics, oCamera);
        }

        public void UpdateCondition(MatchScreen3D oMatchScreen)
        {
            Condition.UpdateTimer();
            if (Condition.IsComplete)
                FinishCondition(oMatchScreen);
        }
        public void StartCondition(bool oIsHost)
        {
            var oDirection = _Direction;
            if (oDirection == Vector3.Zero)
                oDirection = _LastDirection;
            if (oDirection != Vector3.Zero)
                oDirection.Normalize();

            switch (Condition.Name)
            {
                case ConditionName.Tackling:
                    {
                        Velocity = oDirection * 0.75f;
                        VelocityZ = 0.5f;
                        _Rotation.X = -MathHelper.PiOver4 * 0.75f;
                        _Friction = FRICTION_DEFAULT;
                        break;
                    }
                case ConditionName.Hopping:
                    {
                        Velocity = oDirection * 0.5f;
                        VelocityZ = 0.5f;
                        _Friction = FRICTION_DEFAULT;
                        _Rotation.X = -MathHelper.PiOver4 * 1.5f;

                        break;
                    }
                case ConditionName.Diving:
                    {
                        Velocity = oDirection;
                        _Friction = FRICTION_DEFAULT * 3;

                        if (_LastDirection.Y < 0)
                            _Rotation.Y = MathHelper.PiOver4 * 0.75f;
                        else
                            _Rotation.Y = -MathHelper.PiOver4 * 0.75f;

                        if (TeamSide == Alliance.Home)
                            _LastDirection = Vector3.UnitX;
                        if (TeamSide == Alliance.Away)
                            _LastDirection = -Vector3.UnitX;

                        break;
                    }
                case ConditionName.Falling:
                    {
                        _Rotation.X = -MathHelper.PiOver2;
                        _Friction = FRICTION_DEFAULT;
                        break;
                    }
                case ConditionName.Shooting:
                    {
                        _Rotation.X = MathHelper.PiOver4 * 0.5f;
                        _Friction = FRICTION_DEFAULT * 4;
                        break;
                    }
                case ConditionName.Neutral:
                default:
                    {
                        _Rotation.X = 0;
                        _Rotation.Y = 0;
                        _Friction = m_fDefaultFriction;
                        break;
                    }
            }
        }
        public void FinishCondition(MatchScreen3D oMatchScreen)
        {
            switch (Condition.Name)
            {
                case ConditionName.Tackling:
                    {
                        FallAfterHitting();
                        Condition.ChangeType(ConditionName.Falling, Condition.ENDTIME_MISS_HIT_FALLING);
                        break;
                    }
                case ConditionName.Diving:
                    {
                        FallAfterHitting();
                        Condition.ChangeType(ConditionName.Falling, Condition.ENDTIME_DIVE);
                        break;
                    }
                case ConditionName.Hopping:
                    {
                        Condition.ChangeTypeToNeutral();
                        StartCondition(true);
                        break;
                    }
                case ConditionName.Falling:
                    {
                        Condition.ChangeTypeToNeutral();
                        StartCondition(true);
                        break;
                    }
                case ConditionName.Shooting:
                    {
                        ShootPuck(oMatchScreen);
                        Condition.ChangeTypeToNeutral();
                        StartCondition(true);
                        break;
                    }
                case ConditionName.Neutral:
                default:
                    {
                        Condition.ChangeTypeToNeutral();
                        StartCondition(true);
                        break;
                    }
            }
        }

        public DrawableObject Drawable
        {
            get { return _HeadDrawable; }
        }

        protected DrawableObject _HeadDrawable;
        protected DrawableObject _HelmetDrawable;
        protected DrawableObject _BodyDrawable;
        protected DrawableObject _EyesDrawable;

        public ControllingPlayer ControllingPlayer
        {
            get { return m_oControllingPlayer; }
            set
            {
                m_bSkipUpdate = true;
                m_oControllingPlayer = value;
            }
        }

        public Alliance TeamSide
        {
            get { return m_eTeam; }
        }

        public Condition Condition
        {
            get;
            set;
        }

        public bool PressingA
        {
            get { return m_bPressingA; }
            set
            {
                PrevPressingA = m_bPressingA;
                m_bPressingA = value;
            }
        }
        public bool PressingB
        {
            get { return m_bPressingB; }
            set
            {
                PrevPressingB = m_bPressingB;
                m_bPressingB = value;
            }
        }
        public bool PressingX
        {
            get { return m_bPressingX; }
            set
            {
                PrevPressingX = m_bPressingX;
                m_bPressingX = value;
            }
        }
        public bool PressingY
        {
            get { return m_bPressingY; }
            set
            {
                PrevPressingY = m_bPressingY;
                m_bPressingY = value;
            }
        }
        public bool PrevPressingA
        {
            get;
            set;
        }
        public bool PrevPressingB
        {
            get;
            set;
        }
        public bool PrevPressingX
        {
            get;
            set;
        }
        public bool PrevPressingY
        {
            get;
            set;
        }

        public List<Moveable3D> HeldObjects
        {
            get { return m_oHeldObjects; }
            set { m_oHeldObjects = value; }
        }

        protected ControllingPlayer m_oControllingPlayer;
        protected bool m_bSkipUpdate;
        protected float m_fDefaultFriction;

        protected const float g_fTranslateRate = 0.25f;
        protected List<Moveable3D> m_oHeldObjects;

        protected bool m_bPressingA;
        protected bool m_bPressingB;
        protected bool m_bPressingX;
        protected bool m_bPressingY;

        protected Alliance m_eTeam;

    }
}
